package org.linlinjava.litemall.wx.web;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.linlinjava.litemall.core.config.DesNoViUtil;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.core.util.bcrypt.BCryptPasswordEncoder;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.service.*;
import org.linlinjava.litemall.db.util.OrderUtil;
import org.linlinjava.litemall.wx.annotation.LoginUser;
import org.linlinjava.litemall.wx.service.GroupBuyService;
import org.linlinjava.litemall.wx.vo.GroupBuyOrder;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import redis.clients.jedis.Jedis;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author zhy
 * @date 2019-07-08 16:59
 **/
@RestController
@RequestMapping("/wx/groupBuy")
public class WxGroupBuyController {
	private final Log logger = LogFactory.getLog(WxGroupBuyController.class);
	@Resource
	private GroupBuyService groupBuyService;

	@Resource
	private LitemallGoodsService goodsService;

	@Resource
	private LitemallGoodsAttributeService goodsAttributeService;

	@Resource
	private LitemallGoodsSpecificationService goodsSpecificationService;

	@Resource
	private LitemallProductService productService;

	@Resource
	private LitemallIssueService goodsIssueService;

	@Resource
	private LitemallUserService userService;

	@Resource
	private LitemallAddressService addressService;

	@Resource
	private LitemallGoodsService litemallGoodsService;

	@Resource
	private LitemallOrderService litemallOrderService;

	private ThreadPoolExecutor executorService = new ThreadPoolExecutor(7, 7, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(20), new ThreadPoolExecutor.CallerRunsPolicy());

	/**
	 * 获取当前团购列表
	 *
	 * @return data
	 */
	@GetMapping("/getGroup")
	public Object getGroup() {
		String currentEndTime = "暂无";
		String nextStartTime = "暂无";
		List<LitemallGroupDetailsVo> goods = null;
		// 找到当前一期的拼团
		LitemallGroupBuy litemallGroupBuy = groupBuyService.findCurrent();
		if (litemallGroupBuy != null) {
			if (litemallGroupBuy.getRunningFlag() == (short)1) {
				litemallGroupBuy.setRunningFlag((short)2);
				groupBuyService.updateRunningFlag(litemallGroupBuy);
			}
			currentEndTime = litemallGroupBuy.getEndTime().getMonthValue() + "月" + litemallGroupBuy.getEndTime().getDayOfMonth() + "日" + litemallGroupBuy.getEndTime().getHour() + "时 结束";
			// 查询商品信息
			List<LitemallGroupBuyDetail> litemallGroupBuyDetails = groupBuyService.getGroupByList(litemallGroupBuy.getId());
			if (litemallGroupBuyDetails.size() > 0) {
				List<Integer> list = litemallGroupBuyDetails.stream().map(e -> Integer.valueOf(e.getGoodId())).collect(Collectors.toList());
				goods = groupBuyService.getGood(list, litemallGroupBuy.getId());
			}
		}
		// 下一期开始时间
		LitemallGroupBuy litemallGroupBuyNext = groupBuyService.findNext();
		if (litemallGroupBuyNext != null) {
			nextStartTime =
				litemallGroupBuyNext.getStartTime().getMonthValue() + "月" + litemallGroupBuyNext.getStartTime().getDayOfMonth() + "日" + litemallGroupBuyNext.getStartTime().getHour() + "时 开始";
		}

		Map<String, Object> data = new HashMap<>(2);
		data.put("currentEndTime", currentEndTime);
		data.put("nextStartTime", nextStartTime);
		data.put("goods", goods);
		return ResponseUtil.ok(data);
	}

	/**
	 * 获取下一期的团购列表
	 *
	 * @return goods
	 */
	@GetMapping("/getNextGroup")
	public Object getNextGroup() {
		List<LitemallGroupDetailsVo> goods = null;
		LitemallGroupBuy litemallGroupBuyNext = groupBuyService.findNext();
		if (litemallGroupBuyNext != null) {
			// 查询商品信息
			List<LitemallGroupBuyDetail> litemallGroupBuyDetails = groupBuyService.getGroupByList(litemallGroupBuyNext.getId());
			if (litemallGroupBuyDetails.size() > 0) {
				List<Integer> list = litemallGroupBuyDetails.stream().map(e -> Integer.valueOf(e.getGoodId())).collect(Collectors.toList());
				goods = groupBuyService.getGood(list, litemallGroupBuyNext.getId());
			}
		}
		Map<String, Object> data = new HashMap<>(2);
		data.put("goods", goods);
		return ResponseUtil.ok(data);
	}

	/**
	 * 根据商品id获取商品详情
	 *
	 * @param id      商品id
	 * @param groupId 团购ID
	 * @return 商品详情
	 */
	@GetMapping("/getGood")
	public Object getGood(@LoginUser Integer userId, Integer id, Integer groupId) {
		if (userId == null) {
			return ResponseUtil.unlogin();
		}
		if (id == null && groupId == null) {
			return ResponseUtil.badArgument();
		}
		//mobile
		FutureTask<LitemallUser> getMobileFutureTask = new FutureTask<>(() -> userService.findById(userId));
		//runningFlag
		FutureTask<LitemallGroupBuy> runningFutureTask = new FutureTask<>(() -> groupBuyService.getGroupById(groupId));
		// 商品信息
		FutureTask<LitemallGoods> groupDetailsVoFutureTask = new FutureTask<>(() -> goodsService.findById(id));
		// 商品属性
		FutureTask<List> goodsAttributeListTask = new FutureTask<>(() -> goodsAttributeService.queryByGid(id));
		// 规格**
		FutureTask<Object> objectCallableTask = new FutureTask<>(() -> goodsSpecificationService.getSpecificationVoList(id));
		//商品规格对应的数量和价格
		FutureTask<List> productListCallableTask = new FutureTask<>(() -> productService.queryByGid(id));
		// 拼团说明
		FutureTask<List> issueCallableTask = new FutureTask<>(() -> goodsIssueService.queryGroup());
		// 拼团比例
		FutureTask<LitemallGroupBuyDetail> groupBuyDetailFutureTask = new FutureTask<>(() -> groupBuyService.getDetail(groupId, id));

		executorService.submit(getMobileFutureTask);
		executorService.submit(runningFutureTask);
		executorService.submit(groupDetailsVoFutureTask);
		executorService.submit(goodsAttributeListTask);
		executorService.submit(objectCallableTask);
		executorService.submit(productListCallableTask);
		executorService.submit(issueCallableTask);
		executorService.submit(groupBuyDetailFutureTask);

		Map<String, Object> data = new HashMap<>(10);

		try {
			data.put("mobile", getMobileFutureTask.get().getMobile());
			data.put("runningFlag", runningFutureTask.get().getRunningFlag());
			data.put("info", groupDetailsVoFutureTask.get());
			data.put("issue", issueCallableTask.get());
			data.put("specificationList", objectCallableTask.get());
			data.put("productList", productListCallableTask.get());
			data.put("attribute", goodsAttributeListTask.get());
			data.put("percent", groupBuyDetailFutureTask.get());
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		return ResponseUtil.ok(data);
	}

	/**
	 * 团购商品用户下单
	 *
	 * @param userId        用户ID
	 * @param groupBuyOrder post参数
	 * @param bindingResult 参数校验
	 * @return 成功或失败
	 * @throws Exception
	 */
	@PostMapping("/submit")
	public Object submit(
		@LoginUser Integer userId, @RequestBody GroupBuyOrder groupBuyOrder, BindingResult bindingResult) throws Exception {
		if (userId == null) {
			return ResponseUtil.unlogin();
		}
		if (bindingResult.getErrorCount() > 0) {
			return ResponseUtil.fail(403, bindingResult.getFieldErrors().get(0).getDefaultMessage());
		}
		try (Jedis jedis = new Jedis("localhost", 6379)) {
			long c = jedis.incr(userId + "groupSubmit");
			if (c > 1) {
				return ResponseUtil.fail(403, "下单过于频繁，稍后再试");
			} else {
				if (c == 1) {
					//设置过期时间
					jedis.expire(userId + "groupSubmit", 1);
				}
			}
		}
		/**
		 * 解密
		 */
		DesNoViUtil tools = new DesNoViUtil();
		Integer addressId;
		String payPassword;
		short num;
		Integer goodId;
		Integer productId;
		Integer groupDetailId;
		try {
			addressId = Integer.parseInt(tools.decode(groupBuyOrder.getAddressId()));
			payPassword = tools.decode(groupBuyOrder.getPayPassword());
			num = Short.parseShort(tools.decode(groupBuyOrder.getNum()));
			goodId = Integer.parseInt(tools.decode(groupBuyOrder.getGoodId()));
			productId = Integer.parseInt(tools.decode(groupBuyOrder.getProductId()));
			groupDetailId = Integer.parseInt(tools.decode(groupBuyOrder.getGroupDetailId()));
		}
		catch (Exception e) {
			e.printStackTrace();
			return ResponseUtil.fail(403, "数据解析失败");
		}
		// 解密完后
		// 2.校验支付密码
		LitemallUser litemallUser = userService.findById(userId);
		BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
		if (payPassword != null && !encoder.matches(payPassword, litemallUser.getPayPassword())) {
			return ResponseUtil.fail(403, "支付密码不对");
		}
		// 3.用户收货地址
		LitemallAddress checkedAddress = addressService.findById(addressId);
		// 4.获取订单商品规格
		LitemallProduct litemallProduct = productService.findById(productId);
		Integer goodsIntegeal = litemallProduct.getIntegral() * num;
		BigDecimal goodsPrice = litemallProduct.getPrice().multiply(new BigDecimal(num));

		if (litemallUser.getBalance().compareTo(goodsPrice) < 0) {
			return ResponseUtil.fail(403, "您的爱币不够");
		}
		if (litemallUser.getIntegral() < goodsIntegeal) {
			return ResponseUtil.fail(403, "您的积分不够");
		}
		// 5.获取商品
		LitemallGoods litemallGoods = litemallGoodsService.findByKeyId(goodId);
		return groupBuyService.submitOrder(litemallUser, goodsIntegeal, goodsPrice, litemallProduct, num, groupDetailId, checkedAddress, litemallGoods);
	}

	/**
	 * 定时任务 下午6点
	 * 将团购时间结束的商品结算有没有达到团购人数
	 * 1.如果达到人数了，将订单id的deleted改为0,,就能发货了
	 * 2.如果没有达到人数，将订单里的账目进行退款
	 */
	@Scheduled(cron = "0 11 12 * * ?")
	@Async
	public void doGroupBuy() {
		logger.info("开始结算");
		LitemallGroupBuy litemallGroupBuy = groupBuyService.findPassed();
		if (litemallGroupBuy != null) {
			try {
				//获取拼团的商品列表
				List<LitemallGroupBuyDetail> litemallGroupBuyDetailList = groupBuyService.getGoodList(litemallGroupBuy.getId());
				for (LitemallGroupBuyDetail litemallGroupBuyDetail : litemallGroupBuyDetailList) {
					if (litemallGroupBuyDetail.getOrderLeftNum() == 0) {
						//加入发货列表
						List<LitemallGroupBuyUser> litemallGroupBuyUsers = groupBuyService.getUsers(litemallGroupBuyDetail.getId());
						List<Integer> orderIds = litemallGroupBuyUsers.stream().map(e -> e.getOrderId()).collect(Collectors.toList());
						//批量更新
						groupBuyService.updateStatus(orderIds);
						//更新user表中的订单状态
						List<Integer> userIds = litemallGroupBuyUsers.stream().map(e -> e.getId()).collect(Collectors.toList());
						groupBuyService.updateUserStatus(userIds, (short)2);
						// 发送模板消息
						for (LitemallGroupBuyUser litemallGroupBuyUser : litemallGroupBuyUsers) {
							groupBuyService.sendGroupSuccessMsg(litemallGroupBuyUser.getUserId(), litemallGroupBuyUser.getGoodName(), litemallGroupBuyUser.getOrderNum());
						}

					} else {
						// 退款,一个一个退
						// 找到订单表中积分与爱币
						List<LitemallGroupBuyUser> litemallGroupBuyUsers = groupBuyService.getUsers(litemallGroupBuyDetail.getId());
						for (LitemallGroupBuyUser litemallGroupBuyUser : litemallGroupBuyUsers) {
							LitemallOrder litemallOrder = litemallOrderService.findById(litemallGroupBuyUser.getOrderId());
							litemallOrder.setOrderStatus(OrderUtil.STATUS_REFUND_CONFIRM);
							Integer integeal = litemallOrder.getActualIntegral();
							BigDecimal price = litemallOrder.getActualPrice();
							groupBuyService.updateUserCount(integeal, price, litemallGroupBuyUser.getUserId(), litemallGroupBuyUser.getId(), litemallGroupBuyUser.getGoodName());
						}
					}
				}
			}
			finally {
				// 全部执行完成后 ，将这一期标志成已完成
				litemallGroupBuy.setRunningFlag((short)3);
				groupBuyService.updateRunningFlag(litemallGroupBuy);
			}
		}
	}
}
